#!/usr/bin/env python
# Copyright (C) 2012 Nanakos Chrysostomos - <cnanakos@ekt.gr>
# National Documentation Centre
# dPool Elasic Cluster - Distributed Image Converting System
# dPool is placed under the GNU General Public License, version 3 or later.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
import zmq
import json
import sqlite3
import uuid
import datetime
import threading
import time
import optparse
import os
import os.path
import sys
import signal
from daemon import runner
import logging
import platform
import setproctitle
import ConfigParser
#dPool Modules
from dutils import ColorAttr,States,Services,DistillerLogger,DistillerTailLog

version = """dPool Version: 0.1"""
usage = """usage: %prog [options] command [arg...]

commands:
  start     start the server daemon
  stop      stop the server daemon
  restart   restart the server daemon
  status    return server daemon status
  log       watch server's logfile (enable DEBUG mode)

Example session:
  %prog start     # starts daemon
  %prog status    # print daemon's status
  %prog log       # watch daemon's logfile (enable DEBUG mode)
  %prog stop      # stops daemon
  %prog restart   # restarts daemon"""



DEBUG_ = True
SERVICE_NAME= "distiller-log"
_conffile='distiller_master.conf'
## Read Configuration variables
config=ConfigParser.RawConfigParser()
config.read(_conffile)

MASTER_SERVER_ENDPOINT=config.get("LOG","MasterServerEndpoint")
LOG_SERVER_REP_ENDPOINT=config.get("LOG","LogServerRepEndpoint")
LOG_SERVER_PUB_ENDPOINT=config.get("LOG","LogServerPubEndpoint")
LOG_PID_FILE=config.get("LOG","LogPIDFile")
LOG_LOG_FILE=config.get("LOG","LogLogFile")
LOG_SERVER_STATUS_ENDPOINT=config.get("LOG","LogServerStatusEndpoint")


class DistillerLog(object):
	def __init__(self,master_endpoint=MASTER_SERVER_ENDPOINT,logserver_endpoint=LOG_SERVER_REP_ENDPOINT,logserver_pub_endpoint=LOG_SERVER_PUB_ENDPOINT):
		self.master_endpoint = master_endpoint
		self.logserver_endpoint = logserver_endpoint
		self.logserver_pub_endpoint = logserver_pub_endpoint
		self.Log = DistillerLogger(LOG_LOG_FILE,"DistillerLogDaemon")

	def createContext(self):
		try:
			self.context = zmq.Context()
			self.logserver = self.context.socket(zmq.REP)
			self.logserver.bind(self.logserver_endpoint)
			self.logserver_pub = self.context.socket(zmq.PUB)
			self.logserver_pub.bind(self.logserver_pub_endpoint)
		except:
			self.Log.logger.error("ZMQ error in createContext()")
			sys.exit(2)
		self.registerLogService()

	def registerLogService(self):
		self.register_service = self.context.socket(zmq.REQ)
                self.register_service.connect(self.master_endpoint)
                self.register_service.send(States.D_REGISTER)
                msg = self.register_service.recv()
                if msg == States.D_TRY:
                        self.register_service.send(json.dumps(dict({"REGISTER_SERVICE":"Log Server","SERVER":platform.node()})))
                        reg_status = self.register_service.recv()
                        if reg_status == States.D_REGISTERED:
                                self.Log.logger.info("Registered to master server")
                        elif reg_status == States.D_REG_ERROR:
                                self.Log.logger.info("Cannot register to master server")
                                sys.exit(2)
                        self.register_service.close()
                        del self.register_service
                elif msg != States.D_TRY:
                        self.Log.logger.info("Message error.Cannot register to master server.")
                        sys.exit(2)

	def run(self):
		statusPublisher = DistillerLogStatus()
                statusPublisher.setDaemon(True)
                statusPublisher.start()
		self.createContext()
		self.serve_forever()
		
	def serve_forever(self):
		while True:
			logmsg = self.logserver.recv()
			self.logserver.send("LOG_MSG_RECV") #States.D_ACK
			self.logserver_pub.send(logmsg)
			self.Log.logger.info(logmsg)
			del logmsg

class DistillerLogStatus(threading.Thread):
        def __init__(self):
                threading.Thread.__init__(self)
        def run(self):
                self.context = zmq.Context()
                self.status = self.context.socket(zmq.REP)
                self.status.bind(LOG_SERVER_STATUS_ENDPOINT)
                self.poller = zmq.Poller()
                self.poller.register(self.status,zmq.POLLIN)
                self.Log = DistillerLogger(LOG_LOG_FILE,"DistillerLogStatus")
                while True:
                        if self.poller.poll(100):
                                try:
                                        msg = self.status.recv()
                                        if msg == States.D_GETSTATUS:
                                                self.status.send(States.D_OK)
                                except Exception, e:
                                        self.Log.logger.error("Error while trying to send ACK heartbeat: %s" % e)


class DistillerLogServer(object):
	def __init__(self):
	        self.stdin_path = '/dev/null'
	        self.stdout_path = '/dev/null'
	        self.stderr_path = '/dev/null'
	        self.pidfile_path =  LOG_PID_FILE
	        self.pidfile_timeout = 5
	def run(self):
		LogServer = DistillerLog()
		LogServer.run()
		

if __name__ == "__main__":

	optparser = optparse.OptionParser(usage=usage,version=version)
	(options, args) = optparser.parse_args()

	setproctitle.setproctitle(SERVICE_NAME)

	if len(args) == 0:
	        optparser.print_help()
	        sys.exit(-1)

	if args[0] == 'start':
		if not os.path.exists(LOG_PID_FILE):
			server = DistillerLogServer()
			daemon_runner = runner.DaemonRunner(server)
			daemon_runner._start()
		else:
			print "PID File exists: %s" % LOG_PID_FILE
	elif args[0] == 'stop':
		if os.path.exists(LOG_PID_FILE):
			server = DistillerLogServer()
			daemon_runner = runner.DaemonRunner(server)
			daemon_runner._stop()
		else:
			print "Log server is not running."
	elif args[0] == 'restart':
		if os.path.exists(LOG_PID_FILE):
			server = DistillerLogServer()
			daemon_runner = runner.DaemonRunner(server)
			daemon_runner._restart()
		else:
			server = DistillerLogServer()
			daemon_runner = runner.DaemonRunner(server)
			daemon_runner._start()
	elif args[0] == 'status':
		if os.path.exists(LOG_PID_FILE):
			fd = open(LOG_PID_FILE,'r')
			pid = fd.readlines()[0].strip()
			fd.close()
			print "Log server is running, PID: %s" % pid
		else:
			print "Log server is not running"
	elif args[0] == 'log':
                log = DistillerTailLog(LOG_LOG_FILE)
		if len(args) == 2: log.tail(int(args[1])) 
                log.follow()
	elif args[0] == 'foreground':
		LogServer = DistillerLog()
		LogServer.run()
	else:
	        optparser.print_help()
	        sys.exit(-1)
